#include "../TimerQueue.h"
#include "../Timer.h"
#include "../TimeId.h"
#include "../EventLoop.h"

namespace yhaida
{
    namespace Timerspace
    {
        int creatTimerfd()
        {
            //创建一个timerFd
            int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
            if (timerfd < 0)
            {
                LOG_SYSFATAL << "Failed in timerfd_create";
            }
            return timerfd;
        }

        // struct timespec
        // {
        //   __time_t tv_sec;		/* Seconds.  */
        //   __syscall_slong_t tv_nsec; /* Nanoseconds.  */
        //  };

        struct timespec setExpirationTime(Timestamp when)
        {
            int64_t microseconds = when.microSecondsSinceEpoch() -
                                   Timestamp::now().microSecondsSinceEpoch();
            if (microseconds < 100)
            {
                microseconds = 100;
            }

            struct timespec ts;
            ts.tv_sec = static_cast<time_t>(microseconds / Timestamp::kMicroSecondsPerSecond);
            ts.tv_nsec = static_cast<long>((microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
            return ts;
        }

        //因为是电平触发所以必须要read()这个触发的timefd
        void readTimerfd(int timerfd, Timestamp nowTime)
        {
            uint64_t howmany;
            int length = ::read(timerfd, &howmany, sizeof(howmany));
            std::string temp = nowTime.toString();
            LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << temp;
            if (length != sizeof(howmany))
            {
                LOG_ERROR << "TimerQueue::handleRead() reads " << length << "bytes instead of 8";
            }
        }
        /*
            1.定时器是根据expiration来排序的，
            2.setExpirationTime(expiration)而根据expiration-now计算
            =>总能保证新插入的时间最短的timer是可以完成的，（会时不时的::timerfd_settime）
        */
        void resetTimerfd(int timerfd, Timestamp expiration)
        {
            // struct itimerspec
            // {
            //     struct timespec it_interval;
            //     struct timespec it_value;
            // };
            struct itimerspec oldtime;
            struct itimerspec newtime;
            memset(&oldtime, 0, sizeof(oldtime));
            memset(&newtime, 0, sizeof(newtime));

            newtime.it_value = setExpirationTime(expiration);
            //设置超时时间，且为相对时间
            int res = ::timerfd_settime(timerfd, 0, &newtime, &oldtime);
            if (res)
            {
                LOG_SYSERR << "timerfd_settime()";
            }
        }
    }
}

using namespace yhaida;
using namespace yhaida::Timerspace;

TimerQueue::TimerQueue(EventLoop *loop)
    : _mainEventLoop(loop),
      _timeFd(creatTimerfd()),
      _timeChannel(_mainEventLoop, _timeFd),
      _timers(),
      _callingExpiredTimers(false)
{
    //初始化_timeChannel
    _timeChannel.setReadCallBackFuc(std::bind(&TimerQueue::handleRead, this));
    _timeChannel.enableReading();
}
TimerQueue::~TimerQueue()
{
    ::close(_timeFd);
    for (auto &item : _timers)
    {
        delete item.second;
    }
}
TimerID TimerQueue::addTimer(TimerCallback fuc, Timestamp when, double interval)
{
    Timer *timer(new Timer(fuc, when, interval));
    _mainEventLoop->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
    return TimerID(timer, timer->sequence());
}
void TimerQueue::addTimerInLoop(Timer *timer)
{
    _mainEventLoop->assertInLoopThread();
    bool ifFirst = insert(timer);
    if (ifFirst)
    {
        //激活定时器
        resetTimerfd(_timeFd, timer->expiration());
    }
}
bool TimerQueue::insert(Timer *timer)
{
    _mainEventLoop->assertInLoopThread();
    assert(_timers.size() == _activeTimers.size());
    bool ifFirst = false;
    Timestamp when = timer->expiration();
    TimeList::const_iterator it = _timers.begin(); //这是第一个计时器
    //_timers里面没有计时器，或者timer的时间最早
    if (it == _timers.end() || when < it->first)
    {
        ifFirst = true;
    }

    {
        auto result = _timers.insert(std::make_pair(when, timer));
        // auto result = _timers.insert(std::make_pair(when, std::move(timer)));
        assert(result.second);
    }
    //保持一致
    {
        auto result = _activeTimers.insert(std::make_pair(timer, timer->sequence()));
        assert(result.second);
        (void)result;
    }
    assert(_timers.size() == _activeTimers.size());
    return ifFirst;
}

void TimerQueue::handleRead()
{
    // 1.得到过期的计时器
    // std::vector<TimerListNode> getExpired(Timestamp now);
    // 2.重置计时器
    // void reset(const std::vector<TimerListNode> &expired, Timestamp now);
    _mainEventLoop->assertInLoopThread();
    Timestamp nowTime(Timestamp::now());
    readTimerfd(_timeFd, nowTime);

    std::vector<TimerListNode> expired = getExpired(nowTime);

    _callingExpiredTimers = true;
    _cancelingTimers.clear();//初始化

    for (auto &item : expired)
    {
        item.second->handleCallback();//在handleCallback可以调用TimerQueue::cancel(TimerID timerID)，因为是回调函数在IO线程所以会马上将取消的timerID加入_cancelingTimers里面
    }
    _callingExpiredTimers = false;

    reset(expired, nowTime);//_cancelingTimers里面已经存放了expired中但是需要取消的timerID
}

//  1.得到过期的计时器
std::vector<TimerQueue::TimerListNode> TimerQueue::getExpired(Timestamp now)
{
    assert(_timers.size() == _activeTimers.size());
    std::vector<TimerListNode> expired;
    TimerListNode plot = std::make_pair(now, reinterpret_cast<Timer *>(UINTPTR_MAX));
    auto it = _timers.lower_bound(plot);
    std::copy(_timers.begin(), it, std::back_inserter(expired));
    _timers.erase(_timers.begin(), it);

    //使_activeTimers，_timers保持一致
    std::for_each(expired.begin(), expired.end(), [this](TimerListNode &node)
                  {
        ActiveTimer timer(node.second, node.second->sequence());
        size_t n = _activeTimers.erase(timer);
        assert(n == 1);
        (void)n; });

    assert(_timers.size() == _activeTimers.size());

    return expired;
}

// 2.重置计时器
void TimerQueue::reset(const std::vector<TimerListNode> &expired, Timestamp now)
{
    Timestamp nextExpireTime;

    for (std::vector<TimerListNode>::const_iterator item = expired.begin();
         item != expired.end();
         ++item)
    {
        ActiveTimer timer(item->second, item->second->sequence());
        if (item->second->isRepeat() //_cancelingTimers取消集合里面不包含
            && _cancelingTimers.find(timer) == _cancelingTimers.end())
        {
            // typedef std::pair<Timestamp, std::unique_ptr<Timer>> TimerListNode;
            // typedef std::set<TimerListNode> TimeList; // set是有序
            item->second->restart(now);
            insert(item->second);
        }
        else
        {
            delete item->second;
        }
    }

    if (!_timers.empty())
    {
        nextExpireTime = _timers.begin()->second->expiration();
    }

    if (nextExpireTime.valid())
    {
        resetTimerfd(_timeFd, nextExpireTime);
    }
}
void TimerQueue::cancel(TimerID timerID)
{
    _mainEventLoop->runInLoop(std::bind(&TimerQueue::cancelTimerInLoop, this, timerID));
}

void TimerQueue::cancelTimerInLoop(TimerID timerID)
{
    _mainEventLoop->assertInLoopThread();
    assert(_timers.size() == _activeTimers.size());

    ActiveTimer timer(timerID._id, timerID._seq);
    auto it = _activeTimers.find(timer);

    if (it != _activeTimers.end())
    {
        size_t n = _timers.erase(TimerListNode(it->first->expiration(), it->first));
        //唯一
        assert(n == 1);
        (void)n;
        delete it->first;
        _activeTimers.erase(it);
    }
    else if (_callingExpiredTimers)//如果不在_activeTimers的话，说明_activeTimers中已经删除了正在calling！
    {
        _cancelingTimers.insert(timer);
    }
    assert(_timers.size() == _activeTimers.size());
}